
/* Generated by Interface Builder */

#import "Oscil.h"
#import "Instrum.h"
#import <appkit/graphics.h>
#import "Statement.h"

@implementation Oscil

+ initialize
{
   	image = [NXImage findImageNamed:"Oscil"];
	ampOffset.x = 17;
	ampOffset.y = 56;
	freqOffset.x = 38;
	freqOffset.y = 56;
	phaseOffset.x = 57;
	phaseOffset.y = 46;
	outOffset.x = 27;
	outOffset.y = 11;
	
	return self;
}

- init
{
	written = NO;
	size.width = 80.;
	size.height = 80.;
	center.x = size.width/2.;
	center.y = size.height/2.;
	strcpy(type,"Oscil");
	strcpy(name,"oscili");
	
	amp = [[Param alloc] init:self :&ampOffset];
	freq = [[Param alloc] init:self :&freqOffset];
	phase = [[Param alloc] init:self :&phaseOffset];
	out = [[Param alloc] init:self :&outOffset];

	[freq setValue:"440"];	// set non-"1" default values
	[phase setValue:"0"];	// set non-"1" default values
	[amp setTitle:"Amp:"];
	[freq setTitle:"Freq:"];
	[phase setTitle:"Phase:"];
	[out setTitle:"Out:"];
	
	paramList = [[List alloc] initCount:4];
	[paramList addObject:amp];
	[paramList addObject:freq];
	[paramList addObject:phase];
	[paramList addObject:out];
	
	[Inst putUgenInList:self];
	
	return self;
}

- remove
{
	id cp,param;
	int i;
							// make sure not connected first 
	for(i = 0; i < ([paramList count]); i++) {	
		param = [paramList objectAt:i];
		if(cp = [param getConnectedParam]) 
			return 0;
	}
							// remove ugen from list
	[Inst removeUgenFromList:self];
	return self;
}

- (NXImage *)getImage
{
	return image;
}

- move:(NXPoint *)newloc
{
	location = *newloc;
	[amp move:&location];
	[freq move:&location];
	[phase move:&location];
	[out move:&location];
	return self;
}

- findParamAtPoint:(NXPoint *)point
{
	NXRect *rect;
	int i;
	id param;
	
	for(i = 0; i < [paramList count]; i++) {
		param = [paramList objectAt:i];
		rect = [param getRect];
		if(NXMouseInRect(point,rect,NO))
			return param;
	}
	//printf("no param found\n");
	return nil;
}

- writeUgen
{
	BOOL am = NO;
	BOOL fm = NO;
	BOOL rm = NO;
	BOOL pi = NO;
	char ampVar[10];
	char freqVar[10];
	/* 	for each input param:
			see if there is input ugen
				if so, grab the output (ug?) and multiply it by this
					param value
				if not just use the param value
	 	after all params done, write relevant code into lists
			(declarations, assignments and loop statements)
			i.e. ug? = oscil(,,,,);
		go to output param connected ugen and call its "writeUgen"
	*/
	int i;
	int parent[3];
	id param;
	id ug;
	id nupar;
	char str[50];
	char par[20];
	
	//printf("writing ugen %d\n",index);
	sprintf(str,"\tfloat ug%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tint len%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tint wave%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tfloat amp%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tfloat si%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tfloat phase%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tfloat out%d;\n",index);
	[Inst putVarInList:str];
	sprintf(str,"\tfloat *f%d;\n",index);
	[Inst putVarInList:str];

	for(i = 0; i < ([paramList count]-1); i++) {	
		param = [paramList objectAt:i];
		if(nupar = [param getConnectedParam]) {
			ug = [nupar getUgen];
			if([ug getWritten] == NO) { 
				parent[i] = [[ug writeUgen] getIndex];
			}
			else  {
				parent[i] = 0;
			}
		}
		else 
			parent[i] = 0;
		
	}
	sprintf(str,"\twave%d = 1;\n",index); // wave
	[Inst putAssignInList:str];
	
	if(parent[0]) { 	// amplitude input ugen	
		//printf("am or ring mod\n");
		rm = YES;
		sprintf(str,"\tamp%d = %.2f;\n",index, 
			atof([[paramList objectAt:0] getValue]));
		[Inst putAssignInList:str];
		sprintf(str,"\tfloat amprm%d;\n",index);
		[Inst putVarInList:str];
		sprintf(str,"\t\tamprm%d = amp%d * ug%d;\n",index,  
			index,parent[0]);
		[Inst putLoopInList:str];
	}
	else {				// amp preset or default
		//printf("amp preset or pfield\n");
		strcpy(par,[[paramList objectAt:0] getValue]);
		if(par[0] == 'p' && par[1] == '[')
			sprintf(str,"\tamp%d = %s;\n", index, par);
		else
			sprintf(str,"\tamp%d = %.2f;\n",index,atof(par));
		[Inst putAssignInList:str];
	}
	if(parent[1]) {
		if(!strcmp([[[freq getConnectedParam] getUgen] getType],"Converter")) { 
			strcpy(par,[[paramList objectAt:1] getValue]);
			sprintf(str,"\tsi%d = ug%d*%.2f*fsize(1)/SR;\n", index, parent[1], atof(par));
		}
		else {
							// fm selected
			strcpy(name,"oscilni");		//printf("fm\n");
			fm = YES;
			sprintf(str,"\tfloat sifm%d;\n",index);
			[Inst putVarInList:str];
			sprintf(str,"\t\tsifm%d = si%d + ug%d * len%d/SR;\n", index,index,parent[1],index);
			[Inst putLoopInList:str];
			sprintf(str,"\tsi%d = %.2f*fsize(1)/SR;\n",index, 
				atof([[paramList objectAt:1] getValue]),index);
		}
		[Inst putAssignInList:str];
	}
	else { 				// freq preset
		//printf("freq preset or pfield\n");
		strcpy(par,[[paramList objectAt:1] getValue]);
		if(par[0] == 'p' && par[1] == '[')
			sprintf(str,"\tsi%d = %s*fsize(1)/SR;\n", index, par);
		else
			sprintf(str,"\tsi%d = %.2f*fsize(1)/SR;\n", index, atof(par));
		[Inst putAssignInList:str];
	}
	
	strcpy(par,[[paramList objectAt:2] getValue]);
	if(par[0] == 'p' && par[1] == '[')
		sprintf(str,"\tphase%d = %s;\n",index,par);
	else
		sprintf(str,"\tphase%d = %.2f;\n", index, atof([[paramList objectAt:1] getValue]));
	
	[Inst putAssignInList:str];
	sprintf(str,"\tlen%d = fsize(wave%d);\n",index,index);
	[Inst putAssignInList:str];
	sprintf(str,"\tf%d = (float *)floc(wave%d);\n",index,index);
	[Inst putAssignInList:str];
	
	if(rm)
		sprintf(ampVar,"amprm%d",index);
	else
		sprintf(ampVar,"amp%d",index);
	if(fm)
		sprintf(freqVar,"sifm%d",index);
	else
		sprintf(freqVar,"si%d",index);
		
					// output amplitude multiplier:
	strcpy(par,[[paramList objectAt:3] getValue]);
	if(par[0] == 'p' && par[1] == '[')
		sprintf(str,"\tout%d = %s;\n",index,par);
	else
		sprintf(str,"\tout%d = %.2f;\n", index, atof([[paramList objectAt:3] getValue]));
	[Inst putAssignInList:str];

	sprintf(str,"\t\tug%d = %s(%s,%s,f%d,len%d,&phase%d)*out%d;\n", index,name,ampVar, freqVar,index,index,index,index);
	
	[Inst putLoopInList:str];
	written = YES;
	return self;	
}

@end
